package cn.witsky.cdrService.domain.base;

import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.witsky.cdrService.domain.callEvent.MoCall;
import cn.witsky.cdrService.util.ByteUtil;
import cn.witsky.cdrService.util.StringUtil;

public class BaseTLV {
	private static Logger logger = LoggerFactory.getLogger(BaseTLV.class);
	private byte[] tagBytes;
	private byte[] valBytes = null;
	private byte[] lenBytes = null;
	private boolean hasChildTLV = false;

	public boolean isHasChildTLV() {
		return hasChildTLV;
	}

	public void setHasChildTLV(boolean hasChildTLV) {
		this.hasChildTLV = hasChildTLV;
	}

	public byte[] getTag() {
		return tagBytes;
	}

	public void setTag(byte[] tag) {
		this.tagBytes = tag;
	}

	public void setValBytes(Value val) {
		this.valBytes = val.toByte();
		this.setLenByte();
		val.clear();
	}
	

	void setValBytes(byte[] bytes) {
		this.valBytes = bytes;
		this.setLenByte();
	}

	private void setLenByte() {
		if (this.valBytes == null || this.valBytes.length == 0) {
			lenBytes = new byte[1];
			lenBytes[0] = 0x00;
		} else if (this.valBytes.length <= 127) {
			lenBytes = new byte[1];
			lenBytes[0] = (byte) this.valBytes.length;
		} else {
			String hexStr = Integer.toHexString(this.valBytes.length);
			int len = hexStr.length();
			int count = len / 2;
			if(len>count*2) {
				count=count+1;
				hexStr="0"+hexStr;
			}
			lenBytes = new byte[count + 1];
			lenBytes[0] = (byte) StringUtil.decodeHEX("8" + count);
			char[] charArr = hexStr.toCharArray();
			char[] newArr = new char[2];
			String newStr = "";
			for (int i = 1; i <= count; i++) {
				newArr[0] = charArr[(i-1) * 2];
				newArr[1] = charArr[(i-1) * 2 + 1];
				newStr = String.valueOf(newArr);
				lenBytes[i] = (byte) StringUtil.decodeHEX(newStr);
			}
		}
	}

	public byte[] getLenBytes() {
		return lenBytes;
	}

	public int getTlvSize() {
		if(this.valBytes==null) {
			return this.tagBytes.length+this.lenBytes.length;
		}else {
			return this.tagBytes.length+this.lenBytes.length+this.valBytes.length;
		}
	}
	public int getLen(BaseTLV tlv) {
		if(tlv.hasChildTLV) {
			Class<?> clz = tlv.getClass();
			Field[] fields = clz.getDeclaredFields();
			int aLLlen=0;
			for (Field field : fields) {
				field.setAccessible(true); // 私有属性必须设置访问权限
				Object resultValue=null;
				try {
					resultValue = field.get(tlv);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if(resultValue!=null) {
					if(resultValue instanceof BaseTLV) {
						BaseTLV chileTLV = (BaseTLV) resultValue;						
						aLLlen=aLLlen+this.getLen(chileTLV);
					}else if(resultValue instanceof List){
						List list=(List) resultValue;
						for(Object obj:list) {
							if(obj instanceof MoCall) {
								BaseTLV chileTLV = (BaseTLV) obj;						
								aLLlen=aLLlen+this.getLen(chileTLV);
							}
						}
					}
				}
			}
			tlv.setValBytes(new byte[aLLlen]);
		}else {
			logger.debug("TLV:{} tag:{} len:{} val:{}",tlv.getClass(),ByteUtil.byteToHex(tlv.tagBytes),ByteUtil.byteToHex(tlv.lenBytes),ByteUtil.byteToHex(tlv.valBytes)) ;
			return tlv.getTlvSize();			
		}
		logger.debug("TLV:{} tag:{} len:{} val:{}",tlv.getClass(),ByteUtil.byteToHex(tlv.tagBytes),ByteUtil.byteToHex(tlv.lenBytes),ByteUtil.byteToHex(tlv.valBytes)) ;
		return tlv.getTlvSize();
	}
	private void writeToFile(DataOutputStream d) {
		try {
			logger.debug("TLV:{} tag:{} len:{} val:{}",this.getClass(),ByteUtil.byteToHex(this.tagBytes),ByteUtil.byteToHex(this.lenBytes)) ;
			d.write(this.tagBytes);
			d.write(this.lenBytes);
			if(this.valBytes!=null) {
				if(!this.hasChildTLV) {
					d.write(this.valBytes);
				}
			}
			d.flush();
		} catch (IOException e) {
			logger.error("写入"+this.getClass()+"出现异常:",e);
		}
		
	}
	public void writeToFile(BaseTLV tlv,DataOutputStream d ) {
		if(tlv.hasChildTLV) {
			tlv.writeToFile(d);
			Class<?> clz = tlv.getClass();
			Field[] fields = clz.getDeclaredFields();
			int aLLlen=0;
			for (Field field : fields) {
				field.setAccessible(true); // 私有属性必须设置访问权限
				Object resultValue=null;
				try {
					resultValue = field.get(tlv);
				} catch (Exception  e) {
					logger.error(tlv.getClass()+"反射获取属性出现异常:",e);
				}
				if(resultValue!=null) {
					if(resultValue instanceof BaseTLV) {
						BaseTLV chileTLV = (BaseTLV) resultValue;						
						this.writeToFile(chileTLV,d);
					}else if(resultValue instanceof List){
						List list=(List) resultValue;
						for(Object obj:list) {
							if(obj instanceof MoCall) {
								BaseTLV chileTLV = (BaseTLV) obj;						
								this.writeToFile(chileTLV,d);
							}
						}
					}
				}
			}
			tlv.setValBytes(new byte[aLLlen]);
		}else {
			tlv.writeToFile(d);			
		}
	}
}
